﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom.Compiler;

namespace WebHelper.Helpers
{
    public class DynamicCodeHelper
    {
        public static Assembly CreateFromPartialCode(string[] refrencedAssemplies, string[] usingNamespaces, string code, string namespaceName, string className, string methodeName, string returnType)
        {
            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerParameters parameters = new CompilerParameters();
            //refrenced assemblies
            if (refrencedAssemplies != null)
            {
                for (int i = 0; i < refrencedAssemplies.Length; i++)
                {
                    parameters.ReferencedAssemblies.Add(refrencedAssemplies[i]);
                }
            }


            string namespaces = "";
            if (usingNamespaces != null)
            {
                for (int i = 0; i < usingNamespaces.Length; i++)
                {
                    namespaces += string.Format("using {0};\r\n", usingNamespaces[i]);
                }
            }
            string completeCode = namespaces + @"[namespaces]

namespace [namespacename]
{
    public class [classname]
    {
        public static [returntype] [methodeName]()
        {
            [code]
        }
    }
}";
            completeCode = completeCode.Replace("[namespaces]", namespaces)
                .Replace("[namespacename]", namespaceName)
                .Replace("[classname]", className)
                .Replace("[returntype]", returnType)
                .Replace("[methodename]", methodeName)
                .Replace("[code]", code);

            // True - memory generation, false - external file generation
            parameters.GenerateInMemory = true;
            // True - exe file generation, false - dll file generation
            parameters.GenerateExecutable = false;

            CompilerResults results = provider.CompileAssemblyFromSource(parameters, completeCode);
            if (results.Errors.HasErrors)
            {
                string errors = string.Empty;
                foreach (CompilerError err in results.Errors)
                {
                    errors += err.ErrorText + " (" + (err.Line-(namespaces.Length+7)) + ")";
                }
                throw new Exception(errors);
            }
            return results.CompiledAssembly;
        }

        public static Assembly CreateFromFiles(string[] refrencedAssemplies, string[] files)
        {
            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerParameters parameters = new CompilerParameters();
            //refrenced assemblies
            if (refrencedAssemplies != null)
            {
                for (int i = 0; i < refrencedAssemplies.Length; i++)
                {
                    parameters.ReferencedAssemblies.Add(refrencedAssemplies[i]);
                }
            }

            // True - memory generation, false - external file generation
            parameters.GenerateInMemory = true;
            // True - exe file generation, false - dll file generation
            parameters.GenerateExecutable = false;

            CompilerResults results = provider.CompileAssemblyFromFile(parameters, files);
            if (results.Errors.HasErrors)
            {
                string errors = string.Empty;
                foreach (CompilerError err in results.Errors)
                {
                    errors +=err.FileName+": " +err.ErrorText + " (" + (err.Line) + ")";
                }
                throw new Exception(errors);
            }
            return results.CompiledAssembly;
        }

        public static Assembly[] GetLoadedAssemplies()
        {
           return AppDomain.CurrentDomain.GetAssemblies();
        }
        
        public static Type[] GetLoadedTypes()
        {
            return DynamicCodeHelper.GetLoadedAssemplies().SelectMany(i =>
             {
                 try
                 {
                     return i.GetTypes();
                 }
                 catch (ReflectionTypeLoadException er)
                 {
                     return er.Types.Where(t => t != null);
                 }
             }).ToArray();
        }

        public static string[] GetLoadedNamespaces()
        {
            return DynamicCodeHelper.GetLoadedTypes().Select(i => i.Namespace).Distinct().ToArray();
        }
                    

    }
}
